#include <iostream>
#include <unistd.h>     // fork()
#include <cstring>      // strlen()
#include <sys/wait.h>   // wait()

using namespace std;

class Writer
{
public:
    Writer(int wfd, const string& s): m_wfd(wfd), m_s(s) {}

    void doSomething()
    {
        char buffer[128];
        int cnt = 0;
        pid_t pid = getpid();

        for(int i = 0; i < 50; ++i)
        {
            snprintf(buffer, sizeof(buffer), m_s.c_str());
            size_t length = strlen(m_s.c_str());
            snprintf(buffer + length, sizeof(buffer) - length, " pid :%d, count :%d\n", pid, cnt);
            write(m_wfd, buffer, strlen(buffer));
            cnt++;
            usleep(1000);   // short blocking of writing to pipe
        }
    }
private:
    string m_s;
    int m_wfd;
};

class Reader
{
public:
    Reader(int rfd): m_rfd(rfd) {}

    void doSomething()
    {
        char buffer[1024];
        int i = 0;
        for(; i < 1000000; ++i)
        {
            read(m_rfd, buffer, sizeof(buffer) - 1);
            printf("%s", buffer);
            m_s += buffer;
            if(i % 10 == 0) { sleep(3); }   // demonstrate blocking from reading
            //sleep(50);  // read_entrance sleeping --- writing blocking
        }
        printf("count until :%d\n", i);
    }

    const string& get_string()
    {
        return m_s;
    }

private:
    string m_s;
    int m_rfd;
};

int test()
{
    // make pipefd to load "in and out" of pipe
    int pipefd[2];
    int n = pipe(pipefd);
    if(n < 0) { return 1; }
    printf("pipefd[0]: %d, pipefd[1] = %d\n", pipefd[0], pipefd[1]);

    string massage = "vocal! father get message:";
    Writer w(pipefd[1], massage);
    Reader r(pipefd[0]);
    
    // the child process writing, father reading
    pid_t id = fork();
    if(id == 0)     // child process code
    {
        close(pipefd[0]);   // close the read entrance

        w.doSomething();

        exit(0);
    }

    close(pipefd[1]);   // close the writing entrance
    r.doSomething();

    // show the massage which transform from child process to father process
    //cout << r.get_string() << endl;

    wait(NULL);
    return 0;
}


int main()
{
    int retern_code = test();
    return retern_code;
}

